package com.jinzhi.jzweb.service.impl;

import com.alibaba.fastjson.support.odps.udf.CodecCheck;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.jinzhi.common.domain.DictDO;
import com.jinzhi.common.service.DictService;
import com.jinzhi.common.utils.Result;
import com.jinzhi.jzweb.domain.StuSignUpComDO;
import com.jinzhi.jzweb.domain.TrackDrawDO;
import com.jinzhi.jzweb.service.StuSignUpComService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.jinzhi.jzweb.dao.TrackDrawRegularDao;
import com.jinzhi.jzweb.domain.TrackDrawRegularDO;
import com.jinzhi.jzweb.service.TrackDrawRegularService;
import com.jinzhi.common.base.CoreServiceImpl;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 *
 * <pre>
 * 赛道抽签表（可以对选手固定赛道）
 * </pre>
 * <small> 2023-10-24 18:52:05 | lance</small>
 */
@Service
public class TrackDrawRegularServiceImpl extends CoreServiceImpl<TrackDrawRegularDao, TrackDrawRegularDO> implements TrackDrawRegularService {

    @Autowired
    private StuSignUpComService stuSignUpComService;

    @Autowired
    private DictService sysDictService;

    /**
     * 赛道抽签可以固定选手的赛道
     * @param trackDrawDTO
     * @return
     */
    @Override
    public Result<List<StuSignUpComDO>> selectDrawRegular(TrackDrawRegularDO trackDrawDTO) {
        //先查询所有参赛选手信息
        Wrapper<StuSignUpComDO> entityWrapper =new EntityWrapper<>();
        List<StuSignUpComDO> stuSignUpComDOS = stuSignUpComService.selectList(entityWrapper);
        if(null == stuSignUpComDOS && stuSignUpComDOS.size()>0){
            return Result.fail("没有参赛选手信息，无法抽签！");
        }

        // 查询字典初始化赛道
        List<String> sessions = new ArrayList<>();
        DictDO dictDO = new DictDO();
        dictDO.setType("trackDrawConfigSubset");
        List<DictDO> list = dictDOList(dictDO);
        if(null != list && list.size()>0){
            for (DictDO  dictDO1 : list){
                sessions.add(dictDO1.getName());
            }
        }

        //存储抽签记录
        List<TrackDrawRegularDO> trackDrawDOList = new ArrayList<>();

        // 根据院校名称分配场次和赛道
        List<String> unitNames = stuSignUpComDOS.stream()
                .map(StuSignUpComDO::getUnitName)
                .distinct()
                .collect(Collectors.toList());
        // 随机打乱院校顺序
        Random random = new Random();
        Collections.shuffle(unitNames, random);

        int j = 0;//同于记录排序
        //先循环院校
        for (String unitName : unitNames) {
            List<StuSignUpComDO> students = stuSignUpComDOS.stream()
                    .filter(student -> student.getUnitName().equals(unitName))
                    .sorted(Comparator.comparing(student -> student.getTrackDraw() == null ? 0 : 1))
                    .collect(Collectors.toList());
            Collections.shuffle(students, random); // 随机打乱院校内的选手顺序
            Collections.shuffle(sessions, random); // 随机打乱赛道
            //用来处理赛道，每抽选完一个就删除一个，当全部抽选完，则表明该院校的选手多于赛道
            LinkedList<String> sessionsBackup = new LinkedList<>(sessions);
            //在循环院校中的选手 循环选手的时候注意 同有个院校的选手要在不同赛道（当选手多于赛道的时候，则允许同有个院校的选手同赛道）
            for (int i = 0; i < students.size(); i++) {
                //如果选手已经固定了，则不需要在随机分配啦
                if(StringUtils.isNotBlank(students.get(i).getTrackDraw())){
                    sessionsBackup.remove(students.get(i).getTrackDraw());
                }
                //对剩下的进行随机分配
                else if (!sessionsBackup.isEmpty()) {
                    String trackDraw = sessionsBackup.get(random.nextInt(sessionsBackup.size()));
                    students.get(i).setTrackDraw(trackDraw);
                    sessionsBackup.remove(trackDraw);
                }
                //如果"sessionsBackup"已经全部抽完了那就从"sessions"中随机再获取
                else {
                    String trackDraw = sessions.get(random.nextInt(sessions.size()));
                    students.get(i).setTrackDraw(trackDraw);
                }
                TrackDrawRegularDO trackDrawRegularDO = new TrackDrawRegularDO();
                BeanUtils.copyProperties(students.get(i),trackDrawRegularDO);
                trackDrawRegularDO.setId(null);
                trackDrawRegularDO.setCreateTime(new Date());
                trackDrawRegularDO.setSort(j++);
                trackDrawDOList.add(trackDrawRegularDO);
            }
        }

        //同时删除之前的抽签结果和批量保存抽签的结果
        EntityWrapper<TrackDrawRegularDO> wrapper = new EntityWrapper<>();
        this.delete(wrapper);
        if(null != trackDrawDOList && trackDrawDOList.size()>0){
            this.insertBatch(trackDrawDOList);
        }

        return Result.ok(stuSignUpComDOS);
    }

    /**
     * 查询赛道信息
     * @param dictDTO
     * @return
     */
    @Override
    public List<DictDO> dictDOList(DictDO dictDTO) {
        List<DictDO> listDictDO;
        Map map = new HashMap();
        if(StringUtils.isNotEmpty(dictDTO.getName()) || StringUtils.isNotBlank(dictDTO.getName())) {
            map.put("Name", dictDTO.getName());
        }
        if(StringUtils.isNotEmpty(dictDTO.getType()) || StringUtils.isNotBlank(dictDTO.getType())) {
            map.put("Type", dictDTO.getType());
        }
        listDictDO = sysDictService.selectListBy(map);
        return listDictDO;
    }


    /**
     * 查询学校
     * @param trackDrawDTO
     * @return
     */
    @Override
    public Result<Set<String>> listSchool(TrackDrawRegularDO trackDrawDTO) {
        EntityWrapper<StuSignUpComDO> entityWrapper = new EntityWrapper<>();
        //先查询所有参赛选手信息
        List<StuSignUpComDO> stuSignUpComDOS = stuSignUpComService.selectList(entityWrapper);
        Set<String> unitNames = new HashSet<>();
        for (StuSignUpComDO stuSignUpComDO : stuSignUpComDOS) {
            unitNames.add(stuSignUpComDO.getUnitName());
        }


        return Result.ok(unitNames);
    }

    @Override
    public TrackDrawRegularDO trackRegularList(TrackDrawRegularDO trackDrawDTO) {
        //存储抽签你信息
        TrackDrawRegularDO resultVO = new TrackDrawRegularDO();
        resultVO.setHasDraw(true);//默认为true.不存在上次抽签结果时改为false

        //查询上一次的抽签结果
        Wrapper<TrackDrawRegularDO> wrapper = new EntityWrapper<>();
        wrapper.orderBy(true,"sort");
        List<TrackDrawRegularDO> trackDrawDOS = this.selectList(wrapper);

        //如果没有抽签上一次抽签结果那就默认初始化
        if(trackDrawDOS==null || trackDrawDOS.size()==0){
            resultVO.setHasDraw(false);
            Wrapper<StuSignUpComDO> entityWrapper =new EntityWrapper<>();
            List<StuSignUpComDO> stuSignUpComDOS = stuSignUpComService.selectList(entityWrapper);
            if(stuSignUpComDOS!=null && stuSignUpComDOS.size()>0){
                for (StuSignUpComDO stuSignUpComDO : stuSignUpComDOS) {
                    TrackDrawRegularDO trackDrawRegularDO = new TrackDrawRegularDO();
                    BeanUtils.copyProperties(stuSignUpComDO,trackDrawRegularDO);
                    trackDrawDOS.add(trackDrawRegularDO);
                }

            }
        }
        resultVO.setTrackDrawDOList(trackDrawDOS);

        return resultVO;
    }


    /**
     * 抽学校
     * @param trackDrawDTO
     * @return
     */
    @Override
    public Result<List<TrackDrawRegularDO>> trackRegularListSchool(TrackDrawRegularDO trackDrawDTO) {
        /**
         * 需要控制学校抽到下午或者上午 （临时需求，暂时先写死）
         * AM：上午  ,  PM:下午
         */
        final String AM = "AM";
        final String PM = "PM";
        Map<String,String> map = new HashMap<>();
        map.put("福州文教职业中专学校2队","PM");

        //先查询所有参赛选手信息
        Wrapper<StuSignUpComDO> entityWrapper =new EntityWrapper<>();
        List<StuSignUpComDO> stuSignUpComDOS = stuSignUpComService.selectList(entityWrapper);
        if(null == stuSignUpComDOS && stuSignUpComDOS.size()>0){
            return Result.fail("没有参赛选手信息，无法抽签！");
        }
        Random random = new Random();

        //返回学校抽签结果
        List<TrackDrawRegularDO> trackDrawDOList = new ArrayList<>();

        // 根据院校名称分配场次和赛道
        Set<String> unitNames = new HashSet<>();
        for (StuSignUpComDO stuSignUpComDO : stuSignUpComDOS) {
            unitNames.add(stuSignUpComDO.getUnitName());
        }
        List<String> keys = new ArrayList<>(unitNames);
        Collections.shuffle(keys, random);

        //遍历 交换得到随机后的结果
        map.forEach((uKey, uValue)->{
            for (int i=0;i<keys.size();i++) {
                //判断是上午还是下午，如果不满足要求，则替换位置   这里判断上午还是下午场就是：总数/2
                if(uKey.equals(keys.get(i))){
                    if(uValue.equals(AM) && i+1>keys.size()/2){
                        //替换位置
                        int dom = random.nextInt(keys.size()/2)+1;//生成1-15的随机数
                        String s = keys.get(dom - 1);
                        keys.set(dom-1,uKey);
                        keys.set(i,s);


                    }
                    else if (uValue.equals(PM) && i<=keys.size()/2){
                        //替换位置
                        int dom = random.nextInt(keys.size()/2) + 16;// 生成16-30之间的随机数
                        String s = keys.get(dom - 1);
                        keys.set(dom-1,uKey);
                        keys.set(i,s);
                    }

                }
            }
        });

        //赋予序号 从1开始
        for (int i = 0; i < keys.size(); i++) {
            TrackDrawRegularDO trackDrawRegularDO = new TrackDrawRegularDO();
            trackDrawRegularDO.setUnitName(keys.get(i));
            trackDrawRegularDO.setSort(i+1);
            trackDrawDOList.add(trackDrawRegularDO);
        }


        //同时删除之前的抽签结果和批量保存抽签的结果
        EntityWrapper<TrackDrawRegularDO> wrapper = new EntityWrapper<>();
        this.delete(wrapper);
        if(null != trackDrawDOList && trackDrawDOList.size()>0){
            this.insertBatch(trackDrawDOList);
        }

        return Result.ok(trackDrawDOList);
    }

    @Override
    public Result<Set<String>> listSignCom(TrackDrawRegularDO trackDrawDTO) {
        EntityWrapper<StuSignUpComDO> entityWrapper = new EntityWrapper<>();
        //先查询所有参赛选手信息
        List<StuSignUpComDO> stuSignUpComDOS = stuSignUpComService.selectList(entityWrapper);
        Set<String> names = new HashSet<>();
        for (StuSignUpComDO stuSignUpComDO : stuSignUpComDOS) {
            names.add(stuSignUpComDO.getName());
        }


        return Result.ok(names);
    }

    @Override
    public Result<List<TrackDrawRegularDO>> trackRegularListSignCom(TrackDrawRegularDO trackDrawDTO) {
        List<TrackDrawRegularDO> trackDrawDOList = new ArrayList<>();

        EntityWrapper<StuSignUpComDO> entityWrapper = new EntityWrapper<>();
        //先查询所有参赛选手信息
        List<StuSignUpComDO> stuSignUpComDOS = stuSignUpComService.selectList(entityWrapper);
        // 根据院校名称分配场次和赛道
        Set<String> names = new HashSet<>();
        for (StuSignUpComDO stuSignUpComDO : stuSignUpComDOS) {
            names.add(stuSignUpComDO.getName());
        }
        Random random = new Random();
        List<String> keys = new ArrayList<>(names);
        Collections.shuffle(keys, random);

        //赋予序号 从1开始
        for (int i = 0; i < keys.size(); i++) {
            TrackDrawRegularDO trackDrawRegularDO = new TrackDrawRegularDO();
            trackDrawRegularDO.setName(keys.get(i));
            trackDrawRegularDO.setSort(i+1);
            trackDrawDOList.add(trackDrawRegularDO);
        }

        //同时删除之前的抽签结果和批量保存抽签的结果
        EntityWrapper<TrackDrawRegularDO> wrapper = new EntityWrapper<>();
        this.delete(wrapper);
        if(null != trackDrawDOList && trackDrawDOList.size()>0){
            this.insertBatch(trackDrawDOList);
        }

        return Result.ok(trackDrawDOList);
    }


}
